package base.core.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;

import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import jakarta.servlet.http.HttpServletResponse;

public class ExcelWrite {

    /**
     * 直接输出到http
     * @param fileName
     * @return
     * @throws IOException
     */
    public Writer writer4Http(String fileName) throws IOException {
        HttpServletResponse response = getResponse(fileName);
        Writer writer = new Writer(response.getOutputStream());
        return writer;
    }

    public Writer writer4Http() throws IOException {
        HttpServletResponse response = getResponse(UUID.randomUUID().toString());
        Writer writer = new Writer(response.getOutputStream());
        return writer;
    }

    /**
     * @param outputStream 可以存储为本地文件或者输出到oss等
     * @return
     * @throws IOException
     */
    public Writer writer(OutputStream outputStream) throws IOException {
        Writer writer = new Writer(outputStream);
        return writer;
    }

    public class Writer {

        private ExcelWriterBuilder writerBuilder;
        private ExcelWriter excelWriter;

        private HashMap<String, Sheeter> sheetMap1 = new HashMap<>();
        private HashMap<Integer, Sheeter> sheetMap2 = new HashMap<>();

        private OutputStream outputStream;
        private InputStream tempStream;

        public Writer(OutputStream outputStream) {
            hashMap.clear();
            writerBuilder = EasyExcel.write(outputStream);
            this.outputStream = outputStream;
        }

        /**
         * excel模版
         */
        public Writer withTemplate(InputStream tempStream) {
            this.tempStream = tempStream;
            if (excelWriter == null) {
                writerBuilder.withTemplate(tempStream);
                build();
            }
            return this;
        }

        private Writer build() {
            if (excelWriter == null) {
                excelWriter = writerBuilder.build();
            }
            return this;
        }

        /**
         * 获取sheet页
         */
        public Sheeter atSheet(String sheetName) {
            Sheeter sheeter = sheetMap1.get(sheetName);
            if (sheeter == null) {
                sheeter = new Sheeter(this, sheetName);
                sheetMap1.put(sheetName, sheeter);
            }
            return sheeter;
        }
        /**
         * 获取sheet页
         */
        public Sheeter atSheet(Integer sheetNo) {
            Sheeter sheeter = sheetMap2.get(sheetNo);
            if (sheeter == null) {
                sheeter = new Sheeter(this, sheetNo);
                sheetMap2.put(sheetNo, sheeter);
            }
            return sheeter;
        }

        /**
         * 结束
         */
        public void end() {
            if (excelWriter != null) {
                excelWriter.finish();
            }
            try {
                outputStream.flush();
            } catch (IOException e) {
            }
            try {
                outputStream.close();
            } catch (IOException e) {
            }
            try {
                tempStream.close();
            } catch (IOException e) {
            }
        }

        public class Sheeter {
            private Writer writer;

            private ExcelWriterSheetBuilder sheetBuilder;

            private Sheeter(Writer writer, String sheetName) {
                this.writer = writer;
                sheetBuilder = EasyExcel.writerSheet(sheetName);
            }

            private Sheeter(Writer writer, Integer sheetNo) {
                this.writer = writer;
                sheetBuilder = EasyExcel.writerSheet(sheetNo);
            }
            /**
             * 设置边框实线黑色
             */
            public Sheeter setBorder() {
                sheetBuilder.registerWriteHandler(getBorderCellWriteHandler());
                return this;
            }

            /**
             * 监听cell的变动
             */
            public Sheeter setListener(Listener listener) {
                sheetBuilder.registerWriteHandler(listener);
                return this;
            }

            /**
             * 是否需要表头
             */
            public Sheeter needHead(boolean isNeedHead) {
                sheetBuilder.needHead(isNeedHead);
                return this;
            }

            /**
             * 写入数据
             */
            public Writer write(List data) {
                if (CollectionUtils.isEmpty(data)) {
                    throw new IllegalArgumentException("data is empty");
                }
                writer.build();
                sheetBuilder.head(data.get(0).getClass());
                writer.excelWriter.write(data, sheetBuilder.build());
                return writer;
            }

            /**
             * 替换数据<br/>
             * 数据格式为{mapKey}
             */
            public Writer replace(Map map) {
                if (map == null) {
                    map = new HashMap();
                }
                writer.build();
                writer.excelWriter.fill(map, sheetBuilder.build());
                return writer;
            }
            /**
             * 替换数据<br/>
             * 数据格式为{mapKey}
             */
            public Writer replace(Collection list) {
                if (list == null) {
                    list = new ArrayList();
                }
                writer.build();
                writer.excelWriter.fill(list, sheetBuilder.build());
                return writer;
            }
        }
    }

    public abstract static class Listener implements CellWriteHandler {
        public abstract void invoke(Cell cell);

        @Override
        public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex,
                                     Boolean isHead) {
            if (!isHead) {
                invoke(cell);
            }
        }
    }

    private HttpServletResponse getResponse(String fileName) throws UnsupportedEncodingException {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        response.reset();
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/x-msdownload");
        String fName = URLEncoder.encode(fileName, "UTF-8");
        response.setHeader("Content-Disposition", "attachment;fileName=" + fName + ".xlsx");
        return response;
    }

    private CellWriteHandler getBorderCellWriteHandler(){
        return new CellWriteHandler() {
            @Override
            public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex,
                                         Boolean isHead) {
                if (!isHead) {
                    setBorderCellStyle(cell);
                }
            }
        };
    }

    private HashMap<String, CellStyle> hashMap = new HashMap();

    /**
     * 设置黑色边框
     */
    public void setBorderCellStyle(Cell cell) {
        String key = "border_comlue_" + cell.getRow().getSheet().getSheetName() + "_" + cell.getColumnIndex();
        CellStyle cellStyle = hashMap.get(key);
        if (cellStyle == null) {
            cellStyle = cell.getSheet().getWorkbook().createCellStyle();
            BeanUtils.copyProperties(cell.getSheet().getColumnStyle(cell.getColumnIndex()), cellStyle);
            hashMap.put(key, cellStyle);
            //上下左右设置黑色边框
            cellStyle.setBorderTop(BorderStyle.THIN);
            cellStyle.setBorderLeft(BorderStyle.THIN);
            cellStyle.setBorderRight(BorderStyle.THIN);
            cellStyle.setBorderBottom(BorderStyle.THIN);
            //防止双击底色变黑
            cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
            cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        }
        cell.setCellStyle(cellStyle);
    }
}